/*
 * AGENT SHERPA
 *  
 * Assignement 2 of the Agent Oriented Software Engineering Course
 * M.Sc. in Advanced Software Engineering (Part-time)
 * University College Dublin www.ucd.ie
 *
 * Copyright (c) 2007 Chris Walsh, Aidan Morrisy and Iain Hull.
 * All rights reserved.
 */

package org.agentsherpa;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.agentsherpa.model.CellType;
import org.agentsherpa.model.Drone;
import org.agentsherpa.model.Point;


/**
 * This is a Readonly Map which super-imposes the location of drones onto the 
 * standard road map.  This is required because the drones move around the map, 
 * while the other CellTypes do not.  super-imposing the drones simplifies both
 * the LocationModule and its clients.
 * 
 * @author iain
 */
public class CompoundMap implements Map<Point, CellType> {
	private final Map<Point, CellType> road;
	private final Map<Point, Drone> dronesByLocation;
	
	public CompoundMap(Map<Point, CellType> road, Map<Point, Drone> dronesByLocation) {
		this.road = road;
		this.dronesByLocation = dronesByLocation;
	}

	public void clear() {
		throw new UnsupportedOperationException("CompoundMap.clear()");
	}

	public boolean containsKey(Object key) {
		return road.containsKey(key) || dronesByLocation.containsKey(key);
	}

	public boolean containsValue(Object value) {
		if (CellType.DRONE == value) {
			return !dronesByLocation.isEmpty();
		}
		return road.containsValue(value);
	}

	public Set<java.util.Map.Entry<Point, CellType>> entrySet() {
		Set<Map.Entry<Point, CellType>> entries = new HashSet<Map.Entry<Point, CellType>>();
		for(Map.Entry<Point, CellType> e : road.entrySet()) {
			if (dronesByLocation.containsKey(e.getKey())) {
				entries.add(new Entry(e.getKey()));
			}
			else {
				entries.add(e);
			}
		}
		return entries;
	}

	public CellType get(Object key) {
		if (dronesByLocation.containsKey(key)) {
			return CellType.DRONE;
		}
		else {
			return road.get(key);
		}
	}

	public boolean isEmpty() {
		return road.isEmpty();
	}

	public Set<Point> keySet() {
		return road.keySet();
	}

	public CellType put(Point key, CellType value) {
		throw new UnsupportedOperationException("CompoundMap.put()");
	}

	public void putAll(Map<? extends Point, ? extends CellType> m) {
		throw new UnsupportedOperationException("CompoundMap.putAll()");
	}

	public CellType remove(Object key) {
		throw new UnsupportedOperationException("CompoundMap.remove()");
	}

	public int size() {
		return road.size();
	}

	public Collection<CellType> values() {
		List<CellType> values = new ArrayList<CellType>();
		for(Map.Entry<Point, CellType> e : road.entrySet()) {
			if (dronesByLocation.containsKey(e.getKey())) {
				values.add(CellType.DRONE);
			}
			else {
				values.add(e.getValue());
			}
		}
		return values;
	}
	
	private class Entry implements Map.Entry<Point, CellType> {
		private Point key;
		private Entry(Point key) {
			this.key = key;
		}
		
		public Point getKey() {
			return key;
		}

		public CellType getValue() {
			return CompoundMap.this.get(key);
		}

		public CellType setValue(CellType value) {
			throw new UnsupportedOperationException("CompoundMap.Entry.setValue()");
		}
		
	}
}
